package edu.amm.api;

/**
 * Сетка, заданная на отрезке.
 * 
 * @author Иванов Илья
 * @since 2013-05-14
 *
 */
public class Mesh {
	
	private Bounds bounds;
	private NodesConfiguration nodesConfig;
	private MeshType meshType;
	
	private Mesh(Bounds bounds, NodesConfiguration nodesConfig, MeshType meshType) {
		this.bounds = bounds;
		this.nodesConfig = nodesConfig;
		this.meshType = meshType;
	}
	
	/**
	 * @return Отрезок, на котором задана сетка.
	 */
	public Bounds getBounds() {
		return bounds;
	}
	
	/**
	 * @return Конфигурация узлов сетки.
	 */
	public NodesConfiguration getNodesConfig() {
		return nodesConfig;
	}
	
	/**
	 * @param nodeIndex Индекс узла от 0 до
	 * <code>this.getNodesConfig().segmentsCount()</code> включительно.
	 * @return Узел по индексу.
	 */
	public double node(int nodeIndex) {
		return nodesConfig.node(nodeIndex, bounds);
	}
	
	/**
	 * @return Тип сетки.
	 */
	public MeshType getMeshType() {
		return meshType;
	}
	
	/**
	 * Тип сетки.
	 * 
	 * @author Иванов Илья
	 * @since 2013-05-16
	 */
	public static enum MeshType {
		
		/**
		 * Сетка общего вида.
		 */
		GENERAL {
			
			public Mesh getInstance(Bounds bounds, NodesConfiguration nodesConfig) {
				return new Mesh(bounds, nodesConfig, this);
			}
		},
		
		/**
		 * Сетка на отрезке [-1, 1].
		 */
		LEGENDRE {
			
			public Mesh getInstance(Bounds bounds, NodesConfiguration nodesConfig) {
				return new Mesh(Bounds.LEGENDRE_BOUNDS, nodesConfig, this);
			}
		};
		
		/**
		 * @param bounds Отрезок, на котором задана сетка.
		 * @param nodesConfig Конфигурация узлов сетки.
		 * @return Построенная сетка.
		 */
		public Mesh instantiate(Bounds bounds, NodesConfiguration nodesConfig) {
			if (bounds == null)
				throw new RuntimeException("Не заданы границы сетки");
			if (nodesConfig == null)
				throw new RuntimeException("Не задана кофигурация узлов сетки");
			
			return getInstance(bounds, nodesConfig);
		}
		
		protected abstract Mesh getInstance(Bounds bounds, NodesConfiguration nodesConfig);
	}
}